package route;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import route.bean.FilterBean;
import route.bean.FunctionBean;
import route.bean.ResultBean;

/**
 *
 * @author meluo
 * @Data 2016/2/3
 */
public class Route implements Filter {

    /**
     * 路由的集合 *
     */
    private Map<String, FunctionBean> routes;

    /**
     * 初始化路由集合
     *
     * @param filterConfig
     * @throws javax.servlet.ServletException *
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("========init==========");
        routes = new HashMap<>();
        String path = Route.class.getResource("/").getPath();
        String websiteURL = (path.replace("/build/classes", "").replace("%20", " ").replace("classes/", "") + "route.xml").replaceFirst("/", "");
        expXml(websiteURL);

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      
        if (request instanceof HttpServletRequest) {
            HttpServletRequest re = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            String url = re.getRequestURI().replace(re.getContextPath() + "/", "");
            if ("".equals(url) || "/TestCrash".equals(url)) {
                RequestDispatcher rd = request.getRequestDispatcher("index.html");
                rd.forward(request, response);
            } else if(url.endsWith(".action")) {
                FunctionBean bean = routes.get(url);
                try {
                   re.setCharacterEncoding("gbk");
                    Map<String, String[]> map = re.getParameterMap();
                    Class<?> function = Class.forName(bean.getRefClass());
                    AbsFunction func = (AbsFunction) function.newInstance();
                    Utils.refField(function, map, func);
                    func.setFilterList(Utils.refFilter(bean.getFilterList(), map, re, resp));
                    func.setRequest(re);
                    func.setResponse(resp);
                    func.beforeExcecute();
                    String ret = func.exe();
                    Map<String, ResultBean> rets = bean.getResultList();
                    ResultBean result = rets.get(ret);
                    if (result == null) {
                       response.setContentType("text/html;charset=gbk");
                        response.getWriter().append(ret);
                        response.getWriter().close();
                    } else {
                        switch (result.getType()) {
                            case "page":
                                RequestDispatcher rd = request.getRequestDispatcher(result.getRetpage());
                                rd.forward(request, response);
                                break;
                            case "redir":
                                resp.sendRedirect(result.getRetpage());
                                break;
                            default:
                                response.setCharacterEncoding("UTF-8");
                                response.getWriter().append(ret);
                                response.getWriter().close();
                                break;
                        }
                    }
                } catch (Exception ex) {
                    Logger.getLogger(Route.class.getName()).log(Level.SEVERE, null, ex);
                    Logger.getLogger(Route.class.getName()).log(Level.SEVERE, null, ex + "\n" + routes.get("appReport").getName());
                    RequestDispatcher rd = request.getRequestDispatcher("error.html");
                    rd.forward(request, response);
                }
            }else {
                  RequestDispatcher rd = request.getRequestDispatcher(url);
                  rd.forward(request, response);
            }
        }
    }

    @Override
    public void destroy() {
        System.out.println("========destroy==========");
    }

    /**
     * 解析XML文件 *
     */
    private void expXml(String path) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File(path));
            Element node = document.getRootElement();
            List<Element> childElements = node.elements();
            for (Element ele : childElements) {
                FunctionBean bean = new FunctionBean();
                String name = ele.attributeValue("name");
                bean.setName(name);
                bean.setRefClass(ele.attributeValue("class"));

                List<FilterBean> filterbeans = new ArrayList<>();
                List<Element> childFilters = ele.elements("filter");
                childFilters.stream().map((eleR) -> {
                    FilterBean f = new FilterBean();
                    f.setErrinfo(ele.elementTextTrim("filter"));
                    f.setRefClass(eleR.attributeValue("class"));
                     f.setRetPage(eleR.attributeValue("retpage"));
                    return f;
                }).forEach((f) -> {
                    filterbeans.add(f);
                });
                bean.setFilterList(filterbeans);
                Map<String, ResultBean> results = new HashMap<>();
                List<Element> childResult = ele.elements("page");
                childResult.stream().forEach((eleR) -> {
                    ResultBean r = new ResultBean();
                    r.setRetpage(eleR.attributeValue("refpage"));
                    r.setRetstr(eleR.attributeValue("retstr"));
                    r.setType(eleR.attributeValue("type"));
                    results.put(eleR.attributeValue("retstr"), r);
                });
                bean.setResultList(results);
                routes.put(name, bean);
            }
        } catch (DocumentException ex) {
            Logger.getLogger(Route.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
